package top.haijunit.springboot.bucket.springsecurity02.security;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import top.haijunit.mark.common.core.Result;
import top.haijunit.mark.common.core.utils.ResponseUtil;
import top.haijunit.springboot.bucket.springsecurity02.entity.UserEntity;
import top.haijunit.mark.common.core.utils.JwtUtil;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;

/**
 * @Author 百旺张
 * @Date 2021/11/11
 * @Description
 */
@Slf4j
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager authenticationManager;

    public TokenLoginFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
        this.setPostOnly(true);
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
    }

    /** 1.获取表单提交用户名和密码 */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            UserEntity dbUser = new ObjectMapper().readValue(request.getInputStream(), UserEntity.class);
            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(dbUser.getUsername(), dbUser.getPassword(), new ArrayList<>()));
        } catch (IOException e) {
            throw new UsernameNotFoundException(e.getMessage(), e);
        }
    }

    /** 2.认证成功调用的方法 */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) {
        // 认证成功，得到认证成功之后用户信息
        UserEntity dbUser = (UserEntity) authResult.getPrincipal();
        // 根据用户名生成token
        String token = JwtUtil.createToken(dbUser.getUsername(), BeanUtil.beanToMap(JSONUtil.createObj().set("username", dbUser.getUsername()).set("userId", dbUser.getUserId())));
        // TODO 可将token和user信息写入到redis中
        ResponseUtil.write(response, Result.ok("登录成功").addData(JwtUtil.tokenName, token));
    }

    /** 3.认证失败调用的方法 */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
        ResponseUtil.write(response, Result.failed("认证失败").addData("error", failed.getMessage()));
    }
}
